//Tranz-Am
#include "game_transam.h"

//local game specifics
static bool newLevelRequired=true;	//new level
static bool WinGame=false;

static Car* Player=NULL;
static int countdown=1;
static long secondsPlayed=0;
static BITMAP* localMap=NULL;

//logic called 1/FPS seconds
bool TransAmGameLogic()
{
	//win
	if(NumCups==MaxNumCups)
	{
		newLevelRequired=true;
		clear_keybuf();
		if(!WinGame)
			GameFramework->SetAutoGameLoopOverride(WinGameLogic,WinGameDrawing);
		else
		{
			NumCups=0;
			GameFramework->ChangeTimerType(GAME_MENU);
		}

		WinGame=true;
		return false;
	}

	//has a new level started
	if(newLevelRequired) 
	{
		if(!InitialiseLevel(true))
			return true;	//exit logic loop and game if failure
	}

	//update relevant in game statistics
	//update counters every second
	if(countdown>=GameConfiguration->CapsSystem.fps)
	{
		countdown=1;
		secondsPlayed++;
	}
	else
		countdown++;

	//update car movement and keyboard handling
	//returns true if exitting (e.g. pressing ESCape)
	if(Player->State==CAR_DYING && Player->car->ReadOnly_Timers[1])
	{
		Player->State=CAR_NORMAL;
		Lives--;
		if(Lives<0) 
		{
			GameFramework->ChangeTimerType(GAME_MENU);
			return false;
		}
		//put in grave
		MapSetBlock(Player->mapx/mapblockwidth,(int)Player->mapy/mapblockheight,GraveBlockNumber);
		
		InitialiseLevel(false);
	}

	//update enemies
	//should really be called after player, but we want the hitcar flag to be kept correct
	for(int i=0;i<MaxEnemies;i++)
	{
		Enemies[i]->NextMove(Player);
	}


	if(Player->NextMove()) 
	{
	//	TempDebug=true;
		CleanUp();
		newLevelRequired=true;
		GameFramework->ChangeTimerType(GAME_MENU);
		return false;
	}

	//move the map the same as the player has moved
	//the car is always in the centre
	mapYoff=Player->mapy-(ShownMapHeight/2);
	mapXoff=Player->mapx-(ShownMapWidth/2);

	//stop falling off, just in case car code doesn't work
	//if(mapYoff+ShownMapHeight>(mapblockheight*mapheight-1))
	//	mapYoff=mapblockheight*mapheight-1-ShownMapHeight;
	//if(mapYoff<0) mapYoff=0;
	//if(mapXoff+ShownMapWidth>(mapblockwidth*mapwidth-1))
	//	mapXoff=mapblockwidth*mapwidth-1-mapXoff;
	//if(mapXoff<0) mapXoff=0;

	//mappy animations
	MapUpdateAnims();
	
	return false;
}

//drawing loop, called 1/FPS seconds
bool TransAmGameDrawing()
{
	clear(GameFramework->DrawingSurface);

	//mappy function to draw the relevant layers
	//draw to the location set up at the start (to the right of the panel)
	//draw to fill the remainder of the screen
	//set starting point within the map to show - at the start it is the approximate centre

	//order is background first, then player car, then any foreground stuff
	//draw map background
	MapDrawBGT (GameFramework->DrawingSurface, (int)mapXoff, (int)mapYoff, ScreenXOffset, ScreenYOffset, ShownMapWidth, ShownMapHeight);

	//draw foreground stuff
	MapDrawFG (GameFramework->DrawingSurface, (int)mapXoff, (int)mapYoff, ScreenXOffset, ScreenYOffset, ShownMapWidth, ShownMapHeight, 0);

	//enemy cars
	//get rough distance from player, nothing fancy as clipping will take care of it
	//	800x600 has a map screen of about 600, 1024 has a screen of about 800
	for(int j=0;j<MaxEnemies;j++)
	{
		if(Enemies[j]->screenx>0 && Enemies[j]->screenx<1000 && Enemies[j]->screeny>0 && Enemies[j]->screeny<1000)
		{
			rotate_sprite(GameFramework->DrawingSurface,Enemies[j]->car->ReadOnly_CurrentItem,
			Enemies[j]->screenx,Enemies[j]->screeny,
			itofix(FIX_ANGLE[Enemies[j]->angle]));

			//temp
			if(Enemies[j]->HitCar)
				rect(GameFramework->DrawingSurface,
				Enemies[j]->screenx+7,Enemies[j]->screeny+7,Enemies[j]->screenx+Enemies[j]->CarWidth-7,
				Enemies[j]->screeny+Enemies[j]->CarHeight-7,makecol(255,0,0));
		}
	}

	//score panel - always top left. maybe only show if screen is > certain size
	blit(DisplayPanel->ReadOnly_CurrentItem,GameFramework->DrawingSurface,0,0,0,0,DisplayPanel->ReadOnly_CurrentItem->w,DisplayPanel->ReadOnly_CurrentItem->h);
	//lives
	for(int i=0;i<Lives;i++)
	{
		draw_sprite(GameFramework->DrawingSurface,PanelCar->ReadOnly_CurrentItem,18+(i*34),424);
	}
	masked_blit(PanelCar->ReadOnly_CurrentItem,GameFramework->DrawingSurface,
		0,PanelCar->ReadOnly_CurrentItem->h-Player->DamageLevel,
		18+(Lives*34),424+PanelCar->ReadOnly_CurrentItem->h-Player->DamageLevel,
		Player->car->ReadOnly_CurrentItem->w,
		Player->DamageLevel);

	//dials
	int speedwidth;
	//pretend block of speed to allow for turbo on road
	if(!Player->BlockTopSpeedIncrease)
		speedwidth=((float)(DisplaySpeedo->ReadOnly_CurrentItem->w-20)/Car::MPH_MAX)*((Player->Mph));
	else
		speedwidth=((float)DisplaySpeedo->ReadOnly_CurrentItem->w/Car::MPH_MAX)*((Player->Mph));

	if(speedwidth>DisplaySpeedo->ReadOnly_CurrentItem->w) speedwidth=DisplaySpeedo->ReadOnly_CurrentItem->w;
	blit(DisplaySpeedo->ReadOnly_CurrentItem,GameFramework->DrawingSurface,0,0,52,293,speedwidth,DisplaySpeedo->ReadOnly_CurrentItem->h);

	int tempwidth;
	tempwidth=(int)(((float)DisplayTemperature->ReadOnly_CurrentItem->w/100)*((Player->Temperature)));
	if(tempwidth>DisplayTemperature->ReadOnly_CurrentItem->w) tempwidth=DisplayTemperature->ReadOnly_CurrentItem->w;
	blit(DisplayTemperature->ReadOnly_CurrentItem,GameFramework->DrawingSurface,0,0,52,374,tempwidth,DisplayTemperature->ReadOnly_CurrentItem->h);

	float Fuelwidth;
	Fuelwidth=((float)(DisplayFuel->ReadOnly_CurrentItem->w/Car::FUEL_MAX))*Player->Fuel;	//60 as that is how long fuel lasts
	if((int)Fuelwidth>DisplayFuel->ReadOnly_CurrentItem->w) Fuelwidth=(float)DisplayFuel->ReadOnly_CurrentItem->w;
	blit(DisplayFuel->ReadOnly_CurrentItem,GameFramework->DrawingSurface,0,0,52,333,(int)Fuelwidth,DisplayFuel->ReadOnly_CurrentItem->h);

	//time and distance
	textprintf_ex(GameFramework->DrawingSurface,font,47,35,makecol(255,255,255),-1,"%03ld:%02ld",secondsPlayed/60,secondsPlayed%60);	
	textprintf_ex(GameFramework->DrawingSurface,font,47,63,makecol(255,255,255),-1,"%06.0f",Player->MilesDriven);	

	//number of cups found
	textprintf_ex(GameFramework->DrawingSurface,font,120,270,makecol(255,255,255),-1,"%d",NumCups);	

	//local radar - map of cups/enemies close up
	//get offset in blocks
	//assume 1 pixel is 1 block, i.e. 80x80 local radar will show 80x80 block radar
	//at 640x480 its about 5 screens, at 800x600 its about 4 screens
	clear_to_color(LocalRadar,bitmap_mask_color(LocalRadar));
	int carblockx=(int)Player->mapx/mapblockwidth;
	int carblocky=(int)Player->mapy/mapblockheight;
	int offset=LocalRadar->w/2;	//assumes a square radar
	int xoff=0;
	int yoff=0;
	for(int n=0;n<MaxNumCups;n++)
	{
		xoff=carblockx-CupPositions[n][0];
		yoff=carblocky-CupPositions[n][1];
		if(!CupPositions[n][2] && abs(xoff)<offset && abs(yoff)<offset)
		{
			//extra 5 pixels is because car is drawn from centre whereas cups/enemies are placed from topleft
			if(TempLocalRadar==1)
				draw_sprite(LocalRadar,LocalCup,offset-xoff-5,offset-yoff-5);
			else
				draw_sprite(LocalRadar,LocalCup,offset+xoff-5,offset+yoff-5);
		}
	}
	//put in enemies if they are close enough
	for(int cars=0;cars<MaxEnemies;cars++)
	{
		//draw on map same way as cups
		xoff=carblockx-((int)Enemies[cars]->mapx/mapblockwidth);
		yoff=carblocky-((int)Enemies[cars]->mapy/mapblockheight);
		//if(abs(Player->mapx-Enemies[cars]->mapx)<320 && abs(Player->mapy-Enemies[cars]->mapy)<320)
		if(abs(xoff)<offset && abs(yoff)<offset)
			//extra 5 pixels is because car is drawn from centre whereas cups/enemies are placed from topleft
			if(TempLocalRadar==1)
				rotate_sprite(LocalRadar,LocalEnemy,offset-xoff-5,offset-yoff-5,itofix(FIX_ANGLE[Enemies[cars]->angle]));
			else
				rotate_sprite(LocalRadar,LocalEnemy,offset+xoff-5,offset+yoff-5,itofix(FIX_ANGLE[Enemies[cars]->angle]));
	}
	//draw the local map and player on the local map
	rotate_sprite(LocalRadar, LocalCar, offset-5,offset-5, itofix(FIX_ANGLE[Player->angle]));	
	draw_sprite(GameFramework->DrawingSurface,LocalRadar,LocalRadarX,LocalRadarY);

	int newx,newy;

	//local map - map of america
	//	draw map
	draw_sprite(GameFramework->DrawingSurface,localMap,LocalMapX,LocalMapY);

	//	put in enemy cars
	for(int i=0;i<MaxEnemies;i++)
	{
		newx=(((int)Enemies[i]->mapx/mapblockwidth)/LocalMapScale);
		newy=(((int)Enemies[i]->mapy/mapblockheight)/LocalMapScale);
		//putpixel(localMap,Enemies[i]->mapx/LocalMapScale,Enemies[i]->mapy/LocalMapScale,makecol(0,0,255));
		rectfill(GameFramework->DrawingSurface,LocalMapX+newx,LocalMapY+newy,LocalMapX+newx+1,LocalMapY+newy+1,makecol(0,0,255));

		//astar
		float destX,destY,screenx,screeny;
		int t=0;
		if(Enemies[i]->RouteGenerated && abs(Enemies[i]->mapx-Player->mapx)<mapblockwidth*30 && abs(Enemies[i]->mapy-Player->mapy)<mapblockwidth*30)
		{
			Enemies[i]->Route->NodeGoFirst();
			while( !Enemies[i]->Route->ReachedGoal())
            {
                Enemies[i]->Route->PathNextNode();
                destX  =  Enemies[i]->Route->NodeGetX();
                destY  =  Enemies[i]->Route->NodeGetY();
				//ensure display is always on a tile exactly
				//_destX=destX/mapblockwidth;
				//_destY=destY/mapblockheight;
				//textprintf_ex(GameFramework->DrawingSurface,font,100,t,
				//	makecol(255,255,255),0,"%f %f",destX, destY);
				//t+=10;

				screenx=destX-mapXoff+ScreenXOffset;
				screeny=destY-mapYoff+ScreenYOffset;

				if(screenx>0 && screenx<1000 && screeny>0 && screeny<1000)
				{
					//draw_sprite(GameFramework->DrawingSurface,LocalCar,screenx,screeny);
					rect(GameFramework->DrawingSurface,screenx,screeny,screenx+mapblockwidth,screeny+mapblockheight,makecol(255,0,0));
				}


            }

			textprintf_ex(GameFramework->DrawingSurface,font,250,40+i*10,makecol(255,0,0),0,"astar!");
		}

	}

	//	draw player on map
	newx=(((int)Player->mapx/mapblockwidth)/LocalMapScale);
	newy=(((int)Player->mapy/mapblockheight)/LocalMapScale);
	rectfill(GameFramework->DrawingSurface,LocalMapX+newx,LocalMapY+newy,LocalMapX+newx+1,LocalMapY+newy+1,makecol(255,0,0));


	//car
	if(Player->car) rotate_sprite(GameFramework->DrawingSurface, Player->car->ReadOnly_CurrentItem, Player->screenx, Player->screeny, itofix(FIX_ANGLE[Player->angle]));

	//debug 
	textprintf_ex(GameFramework->DrawingSurface,font,0,0,makecol(255,255,255),0,"maxw %d maxh %d angle %d vel %f mph %d FPS %d",mapblockwidth*mapwidth-1,mapblockheight*mapheight,Player->angle,Player->vel,Player->Mph,TimerCurrentFPS);
	textprintf_ex(GameFramework->DrawingSurface,font,180,10,makecol(255,255,255),0,"Version 8. x %d y %d",(int)Player->mapx/mapblockwidth,(int)Player->mapy/mapblockheight);
	for(int x=0;x<MaxNumCups;x++)
		textprintf_ex(GameFramework->DrawingSurface,font,570,x*10,makecol(255,255,255),1,"%d:%d %d",CupPositions[x][0],CupPositions[x][1],CupPositions[x][2]);

	if(Player->HitCar)
		rect(GameFramework->DrawingSurface,
			Player->screenx+7,Player->screeny+7,Player->screenx+Player->CarWidth-7,
			Player->screeny+Player->CarHeight-7,makecol(255,0,0));

	return false;
}

/**********************************************
	local helper functions
*/

//initialise the new level
bool InitialiseLevel(bool Reload)
{
	newLevelRequired=false;
	WinGame=false;

	if(Reload)
	{
		secondsPlayed=0;
		NumCups=0;
		if(!LoadLevel())		//load map
		{
			Configuration::GlobalErrorString="Could not initialise map. Check log file and the transam.fmp file exists.";
			return false;
		}
	
		//initialise local map
		if(localMap) destroy_bitmap(localMap);
		if(is_video_bitmap(LocalMap))
			localMap=create_video_bitmap(LocalMap->w,LocalMap->h);
		else if (is_system_bitmap(LocalMap))
			localMap=create_system_bitmap(LocalMap->w,LocalMap->h);
		else
			localMap=create_bitmap(LocalMap->w,LocalMap->h);
		clear_to_color(localMap,bitmap_mask_color(localMap));
		draw_sprite(localMap,LocalMap,0,0);

		//	put in petrol stations and roads
		BLKSTR* tmp;
		for(int y=0;y<mapheight;y++)
		{
			for(int x=0;x<mapwidth;x++)
			{
				tmp=MapGetBlock(x,y);
				if(tmp->unused2)	//road
					putpixel(localMap,x/LocalMapScale,y/LocalMapScale,makecol(229,167,1));
				if(tmp->unused1)	//petrol
					putpixel(localMap,x/LocalMapScale,y/LocalMapScale,makecol(255,255,255));
			}
		}
	}

	RegenerateAstarMap();

	//initialise the location of what part of the map (top left) we show - the middle
	mapXoff=(mapblockwidth*mapwidth)/2;
	mapYoff=(mapblockheight*mapheight)/2;

	//initialise the car
	Player->SetupCar("player",Reload);
	for(int i=0;i<MaxEnemies;i++)
		Enemies[i]->SetupCar();

	//initialise the car location to be the current map location, but in the centre
	Player->mapx=mapXoff+(ShownMapWidth/2);
	Player->mapy=mapYoff+(ShownMapHeight/2);
	MapSetBlockInPixels(Player->mapx,Player->mapy,CupBlockFreeNumber);	//ensure start position does not have anything, e.g. a grave

	return true;
}

void RegenerateAstarMap()
{
	//regenerate map (1 blocked, 0 open)
	BLKSTR* CurrentBlock;
	if(AstarMap) delete AstarMap;
	AstarMap=new int[mapwidth*mapheight];
	for(int i=0;i<mapheight;i++)
		for(int j=0;j<mapwidth;j++)
		{
			CurrentBlock=MapGetBlock(j,i);
			if((CurrentBlock->tl))
			{
				AstarMap[i*mapwidth+j]=1;
			}
			else
			{
				AstarMap[i*mapwidth+j]=0;
			}

			//AstarMap[i*mapwidth+j]=0;	//go anywhere for now
		}
}

//reset everything
void CleanUp()
{
	//player
	if(Player) delete Player;
	Player=NULL;

	for(int i=0;i<MaxEnemies;i++)
	{
		if(Enemies[i]) delete Enemies[i];
		Enemies[i]=NULL;
	}

	//local map
	if(localMap)
	{
		destroy_bitmap(localMap);
		localMap=NULL;
	}

	//astar
	if(AstarMap) 
		delete AstarMap;
	AstarMap=NULL;

	//mappy
	//initial map file, try VRAM is paging or triple buffering
	MapFreeMem();
	
}

bool LoadLevel()
{
	//starts the level
	//does not perform resetting of all data as may be just a new life
	CleanUp();
	
	//cars and enemies
	Player=new Car();
	for(int i=0;i<MaxEnemies;i++)
		Enemies[i]=new EnemyCar();

	int loaded=1; //default to not loaded
	
	//sort out levels later, for now just one
	//determine if we should load up into VRAM or standard memory
	//mappy doesn't support system bitmaps
	if(GameConfiguration->CapsActualSystem.GraphicsMode==MODE_PAGED || GameConfiguration->CapsActualSystem.GraphicsMode==MODE_TRIPLE)
	{
		loaded=MapLoadVRAM("transam.fmp");
		if(loaded!=0) Configuration::LogEntry("Buffer is VRAM but could not load map into vram, using standard");
		else Configuration::LogEntry("loaded map into VRAM");
	}
	if(loaded!=0)
	{
		loaded=MapLoad ("transam.fmp");
		if(loaded!=0) Configuration::LogEntry("Buffer is not VRAM but could not load map into memory! crikey!");
		else Configuration::LogEntry("loaded map into memory");
	}
	if(loaded!=0) return false;
	
	//mappy initialisation
	MapGenerateYLookup();
	MapInitAnims ();
	
	//generate a bitmap
	//BITMAP* map=create_bitmap(1024,768);
	//BLKSTR* tmp;
	//clear(map);
	//for(int y=0;y<mapheight;y++)
	//{
	//	for(int x=0;x<mapwidth;x++)
	//	{
	//		tmp=MapGetBlock(x,y);
	//		if(tmp->user4==9)
	//			putpixel(map,x,y,makecol(255,255,255));
	//			
	//	}
	//}
	//save_bitmap("map.bmp",map,NULL);
	//destroy_bitmap(map);
	
	//place cups
	int cupsPlaced=0;
	int x,y;
	BLKSTR* block;
	while(cupsPlaced<MaxNumCups)
	{
		x=rand() % mapwidth;
		y=rand() % mapheight;
		block=MapGetBlock (x,y);
		if(block->br)
		{
			CupPositions[cupsPlaced][0]=x;
			CupPositions[cupsPlaced][1]=y;
			CupPositions[cupsPlaced][2]=0;	//found
			cupsPlaced++;
			MapSetBlock(x,y,CupBlockNumber);
		}
	}
	return true;	
}

